package org.beynet.docs.http;

import java.io.IOException;
import java.io.InputStream;
import java.util.regex.Pattern;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.apache.log4j.Logger;
import org.beynet.docs.helpers.XmlHelper;
import org.beynet.docs.session.Session;
import org.w3c.dom.Document;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

public class HttpHelper {
    
    /**
     * parse into a dom tree an xml document received throw http
     * @param httpStream
     * @param expectedLength
     * @param encoding
     * @return
     * @throws SAXException
     * @throws IOException
     */
    public static Document parseHttpXmlStreamIntoDom(InputStream httpStream,long expectedLength,String encoding) throws SAXException, IOException{
        try {
            InputSource source = new InputSource();
            if (encoding!=null) source.setEncoding(encoding);
            source.setByteStream(httpStream);
            return(XmlHelper.getDocumentBuilder().parse(source));
        } finally {
            httpStream.close();
        }
    }
    
    /**
     * return the status code and close the resources used - to be used when just the status code
     * is interesting
     * @param response
     * @return
     * @throws IOException
     */
    public static int getStatusCodeAndReleaseResource(HttpResponse response) throws IOException {
        int status = response.getStatusLine().getStatusCode();
        releaseResource(response);
        return(status);
    }
    
    /**
     * release resources 
     * @param response 
     */
    public static void releaseResource(HttpResponse response) throws IOException{
        HttpEntity entity = response.getEntity();
        if (entity==null) return;
        InputStream is = null;
        try {
            is= entity.getContent();
        } finally {
            if (is!=null) is.close();
        }
    }
    
    /**
     * create a post query with the mandatory headers
     * @param session
     * @param URL
     * @return
     */
    public static HttpPost createPostRequest(Session session,String URL) {
        HttpPost   postQuery = new HttpPost(URL);
        postQuery.addHeader("Authorization", session.getAuthorizationHeaderValue());
        postQuery.addHeader(GDocsHTTPConstants.API_VERSION, "3.0");
        return(postQuery);
    }
    
    /**
     * create a new put request
     * @param session
     * @param URL
     * @return
     */
    public static HttpPut createPutRequest(Session session,String URL) {
        HttpPut   putQuery = new HttpPut(URL);
        putQuery.addHeader("Authorization", session.getAuthorizationHeaderValue());
        putQuery.addHeader(GDocsHTTPConstants.API_VERSION, "3.0");
        return(putQuery);
    }
    
    /**
     * create a new delete request
     * @param session
     * @param URL
     * @return
     */
    public static HttpDelete createDeleteRequest(Session session,String URL) {
        HttpDelete   deleteQuery = new HttpDelete(URL);
        deleteQuery.addHeader("Authorization", session.getAuthorizationHeaderValue());
        deleteQuery.addHeader(GDocsHTTPConstants.API_VERSION, "3.0");
        return(deleteQuery);
    }
    
    /**
     * return an httpclient for current thread
     * @return
     */
    public static HttpClient getHttpClient(){
        return(httpClient);
    }
    
    @Deprecated
    public static HttpClient getNewHttpClient(){
        logger.debug("force optention of a new http client");
        return(httpClient);
    }
    
    public final static String CONTENT_TYPE = "Content-Type";
    public final static String LOCATION_HEADER = "Location";
    public final static String CONTENT_RANGE_HEADER = "Content-Range";
    
    public final static Pattern CHARSET_PATTERN = Pattern.compile(".*charset=([^;]*);.*",Pattern.CASE_INSENSITIVE);
    
    /*private static ThreadLocal<HttpClient> httpClients = new ThreadLocal<HttpClient>() {
        @Override
        protected HttpClient initialValue() {
            return(new DefaultHttpClient());
        }
    };*/
    static {
            SchemeRegistry schemeRegistry = new SchemeRegistry();
            schemeRegistry.register(
                    new Scheme("http", 80, PlainSocketFactory.getSocketFactory()));
            schemeRegistry.register(
                    new Scheme("https", 443, SSLSocketFactory.getSocketFactory()));
            ThreadSafeClientConnManager cm = new ThreadSafeClientConnManager(schemeRegistry);
            // Increase max total connection to 200
            cm.setMaxTotal(200);
            // Increase default max connection per route to 20
            cm.setDefaultMaxPerRoute(20);
            // Increase max connections for localhost:80 to 50
            httpClient = new DefaultHttpClient(cm);
    }
    private static final HttpClient httpClient ;
    private final static Logger logger = Logger.getLogger(HttpHelper.class);
}
